package com.fla.puzzle.ui.game;

import java.util.HashMap;
import java.util.Map;

import com.fla.puzzle.PackDataProvider;
import com.fla.puzzle.PuzzleApplication;
import com.fla.puzzle.R;
import com.fla.puzzle.utils.AndroidUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.widget.CompoundButton;
import android.widget.ToggleButton;

/**
 * Holds puzzle's image and provides access to its parts
 * 
 * @author Q-MAE
 */
public class FieldViewProvider {
    private static final int MARGIN_DP = 2;

    private PackDataProvider packDataProvider = PuzzleApplication.getInstance().getPackDataProvider();

    private Context context;

    private final int fieldWidth;
    private final int fieldHeight;

    private int marginPx;

    private Map<GameField, Bitmap> cachedBitmaps = new HashMap<GameField, Bitmap>();

    public FieldViewProvider(Context context, GameModel gameModel, int fullWidth, int fullHeight) {
        this.context = context;
        this.fieldWidth = fullWidth / gameModel.getColsCount();
        this.fieldHeight = fullHeight / gameModel.getRowsCount();

        marginPx = AndroidUtils.dpToPx(context.getResources(), MARGIN_DP);

        // cashe it
        Bitmap bitmap = packDataProvider.loadBitmap(gameModel.getPackItem().getImageId(), fullWidth, fullHeight);

        int bitmapFieldWidth = bitmap.getWidth() / gameModel.getColsCount();
        int bitmapFieldHeight = bitmap.getHeight() / gameModel.getRowsCount();

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale((fieldWidth - marginPx) / (float) bitmapFieldWidth, (fieldHeight - marginPx)
            / (float) bitmapFieldHeight);

        for (GameField gameField : gameModel.getOrderedFields()) {
            int x = gameField.x * bitmapFieldWidth;
            int y = gameField.y * bitmapFieldHeight;

            cachedBitmaps.put(gameField,
                Bitmap.createBitmap(bitmap, x, y, bitmapFieldWidth, bitmapFieldHeight, scaleMatrix, false));
        }
    }

    public void closeResources() {
        cachedBitmaps.clear();
    }

    /**
     * Creates view for the given field to be shown in the game's field
     * 
     * @param gameField {@link GameField}
     * @return CompoundButton field's view
     */
    public CompoundButton createFieldView(GameField gameField) {
        CompoundButton fieldView = new ToggleButton(context);
        fieldView.setBackgroundResource(R.drawable.game_field_bg);

        applyGameField(fieldView, gameField);

        return fieldView;
    }

    /**
     * Swaps the content of the given field's views
     * 
     * @param view1 CompoundButton the first field view
     * @param view2 CompoundButton the second field view
     */
    public void swapContent(CompoundButton view1, CompoundButton view2) {
        GameField field1 = obtainGameField(view1);
        GameField field2 = obtainGameField(view2);

        applyGameField(view1, field2);
        applyGameField(view2, field1);
    }

    /**
     * Returns {@link GameField} assotiated with the given field view
     * 
     * @param view CompoundButton field view
     * @return {@link GameField}
     */
    public GameField obtainGameField(CompoundButton view) {
        return (GameField) view.getTag();
    }

    private void applyGameField(CompoundButton fieldView, GameField gameField) {
        fieldView.setTag(gameField);

        fieldView.setButtonDrawable(new CenterDrawable(cachedBitmaps.get(gameField)));
        // workaround!!!
        // after setting the button the height of the view changes!
        fieldView.setHeight(fieldHeight);
    }

    private class CenterDrawable extends LayerDrawable {
        public CenterDrawable(Bitmap bitmap) {
            super(new Drawable[] {new BitmapDrawable(context.getResources(), bitmap)});
        }

        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            int shift = marginPx / 2;
            // by default in compound button this drawable is drawn on the left,
            // so we need to shift it to the center
            super.setBounds(left + shift, top, right + shift, bottom);
        }
    }

}
